package com.miku.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Test;

/**
 * 对象转换工具
 * @author 杜金伟 [2016年2月28日 上午11:52:26]
 */
public class ObjectConvertUtils {
	private static Map<String, Map<String, Method>> clazzMap = new HashMap<String, Map<String, Method>>();
	
	/**
	 * 对一个数据行转换为一个实际的bean对象
	 * 该函数会一一赋值到bean里面，调用bean的set函数
	 * bean必须要保证其属性的顺序和row的列顺序一致，否则会造成异常的发生
	 * 对于可能的类型转换，他会自动执行，例如：String->int、BigInteger->int
	 * @param row  数据行
	 * @param obj   对象实例，请使用new Object的形式new一个对象进来即可
	 * @return
	 */
	public static<T> T transToObject(Object[] row, T obj){
		if(row == null || obj == null) return null;
		
		Class<?> clz = obj.getClass();
		Map<String, Method> classMethodMap = clazzMap.get(clz.getName());
		if(classMethodMap == null){
			/**
			 * 保证只有一个线程在修改clazzMap
			 */
			synchronized (clazzMap) {
				classMethodMap = new HashMap<String, Method>();
				Method[] mds = clz.getDeclaredMethods();
				for(int i = 0; i < mds.length; ++i){
					String lastName = mds[i].getName();
					Class<?>[] methodParamTypes = mds[i].getParameterTypes();
					
					//比如有且只有一个参数的set函数才会加入
					if(methodParamTypes != null && methodParamTypes.length == 1 &&
						lastName != null && lastName.length() > 3 && 
						lastName.subSequence(0, 3).equals("set")){
						
						lastName = lastName.substring(3).toLowerCase();
						classMethodMap.put(lastName, mds[i]);
					}
				}
				clazzMap.put(clz.getName(), classMethodMap);
			}
		}
		
		try{
			Object ins = obj;
			Field fds[] = clz.getDeclaredFields();
			int looped = Math.min(fds.length, row.length);
			for(int i = 0; i < looped; ++i){
				String name = fds[i].getName().toLowerCase();
				Method md = classMethodMap.get(name);
				if(md != null){
					Class<?> argsType[] = md.getParameterTypes();
					if(row[i] != null){
						Class<?> valueType = row[i].getClass();
						Class<?> argType = argsType[0];
						
						if(argType.equals(valueType)){
							md.invoke(ins, row[i]);	
							continue;
						}
	
						if(valueType.equals(BigInteger.class)){
							md.invoke(ins, ((BigInteger)row[i]).intValue());
						}else if(valueType.equals(String.class)){
							String v = row[i].toString();
							if(v.equals("")) v = "0";
							
							if(argType.equals(Integer.class) || argType.equals(int.class)){
								md.invoke(ins, Integer.parseInt(v));
							}else if(argType.equals(Float.class) || argType.equals(float.class)){
								md.invoke(ins, Float.parseFloat(v));
							}else if(argType.equals(Long.class) || argType.equals(long.class)){
								md.invoke(ins, Long.parseLong(v));
							}else if(argType.equals(Double.class) || argType.equals(double.class)){
								md.invoke(ins, Double.parseDouble(v));
							}else if(argType.equals(String.class)){
								md.invoke(ins, row[i].toString());
							}else{
								//对于其他类型，直接赋值
								//System.out.println("arg = " + argType.getName() + ", value = " + valueType.getName());
								md.invoke(ins, row[i]);
							}
						}else{
							if(argType.equals(String.class)){
								//对于其他类型，直接赋值
								md.invoke(ins, row[i].toString());
							}else{
								//对于其他类型，直接赋值
								md.invoke(ins, row[i]);
							}
						}
					}
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		return obj;
	}
	
	/**
	 * 工具函数调试方法
	 */
	@Test
	public void t(){
		Object [] os = new Object[10];
		os[0] = "品牌名";
		os[1] = "产品名";
		os[2] = 1;//"测试2";
		os[3] = "描述";
		os[4] = 3;
		os[5] = 4;
		
		List<Object[]> list = new ArrayList<Object[]>();
		list.add(os);
		list.add(os);
		list.add(os);
		list.add(os);
		list.add(os);
		list.add(os);
		list.add(os);
		list.add(os);
		list.add(os);
		//List<SearchKeywordResultResp> r = transToObjectArray(list, SearchKeywordResultResp.class);
		//System.out.println(JSON.toJSONString(r));		
	}
	
	/**
	 * 查询结果到实体类映射函数
	 * 请必须保证查询结果和实体类的对应关系，即第一个属性对应第一列，第二个对应第二个，以此类推，否则会异常
	 * @param objs      提供通过查询得到的数据集Object对象列表，一般是hibernate等的sql查询结果
	 * @param clazz     提供转换到的类别class
	 * @return  返回转换的结果列表
	 */
	@SuppressWarnings("unchecked")
	public static <T> List<T> transToObjectArray(List<Object[]> objs, Class<?> clazz){
		List<T> r = new ArrayList<T>();
		try{ 
			for(int i = 0; i < objs.size(); ++i){
				r.add((T) transToObject(objs.get(i), clazz.newInstance()));
			}
		}catch(Exception e){
			e.printStackTrace();
			r = null;
		}
		return r;
	}
}